﻿using Newtonsoft.Json.Linq;
using Maltose.Cache;
using Maltose.Encrypt;
using System;
using Maltose.Configuration;

namespace Maltose.DynamicToken
{
    /// <summary>
    /// 动态令牌生成器 可用于生成 webapi 的 token
    /// </summary>
    public class UseDynamicToken
    {
        /// <summary>
        /// token过期时间 默认 2小时 单位秒
        /// </summary>
        public int ExpireTime { get; private set; }

        /// <summary>
        /// 加密的密钥 默认读配置文件 Dynamic.Token.Key 节点内容
        /// </summary>
        public string EncryptKey { get; private set; }



        /// <summary>
        /// 动态令牌生成器
        /// </summary>
        /// <param name="encryptKey">加密key</param>
        /// <param name="expireTime">过期时间 单位秒</param>
        public UseDynamicToken(string encryptKey, int expireTime = 7200)
        {
            EncryptKey = encryptKey;
            ExpireTime = expireTime;
        }

        /// <summary>
        /// Token转为存在缓存中的真实键
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public string GetRealKey(string token)
        {
            try
            {
                var str = UseEncrypt.Decrypt(EncryptKey, token, DecryptType.AESUnsigned);
                return str.JsonToObject<DynamicTokenKey>().K;
            }
            catch (Exception)
            {
                return string.Empty;
            }

        }

        /// <summary>
        /// 创建一个 token
        /// </summary>
        /// <param name="searchKey"></param>
        /// <returns></returns>
        string CreateTokenString(string searchKey)
        {
            //加密的字符串
            var token = new DynamicTokenKey()
            {
                K = searchKey,
                T = UseEncrypt.MD5($"{Guid.NewGuid().ToString().Replace("-", "")}").ToLower()
            };
            //生成Token 值
            return UseEncrypt.Encrypt(EncryptKey, token.ToJson(), EncryptType.AESUnsigned);
        }

        /// <summary>
        /// 创建一个新的 token
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="searchKey">用于缓存搜索的key</param>
        /// <param name="data">需要加入的自定义数据</param>
        /// <returns></returns>
        public string CreateToken<T>(string searchKey, T data) where T : class, new()
        {
            var newToken = CreateTokenString(searchKey);
            var conten = new DynamicTokenCache<T>()
            {
                Token = newToken,
                ExpireDateTime = DateTime.Now.AddSeconds(ExpireTime),
                Data = data
            };
            UseCache.Instance.Add(searchKey, conten.ToJson(), TimeSpan.FromSeconds(ExpireTime));
            return newToken;
        }

        /// <summary>
        /// 获取自定义数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="token">token</param>
        /// <returns></returns>
        public T GetCustomData<T>(string token) where T : class, new()
        {
            //解密 token 得到key
            var key = GetRealKey(token);
            if (string.IsNullOrWhiteSpace(key))
            {
                return default;
            }
            var value = UseCache.Instance.Get(key);
            if (!string.IsNullOrWhiteSpace(value)) 
            {
                return JObject.Parse(value)["Data"].ToObject<T>();
            }
            return default;
        }

        /// <summary>
        /// 判断当前授权token是否正确/存在
        /// </summary>
        /// <param name="token">原始token</param>
        /// <param name="type">验证类型</param>
        /// <returns></returns>
        public TokenContent Validate(string token, ValidateType type = ValidateType.None)
        {
            var rawKey = GetRealKey(token);
            var rs = new TokenContent();

            if (string.IsNullOrWhiteSpace(rawKey))
            {
                rs.State = TokenContentStateType.DecryKeyError;
                rs.Msg = "密钥解密错误";
            }

            var rawData = UseCache.Instance.Get(rawKey)?.ToString();
            if (string.IsNullOrWhiteSpace(rawData))
            {
                rs.State = TokenContentStateType.ExpirePassOrInvalid;
                rs.Msg = "token无效或者已过期";
                return rs;
            }
            var data = rawData.JsonToObject<DynamicTokenCache<object>>();
            //对比新的 token
            if (token != data.Token)
            {
                rs.State = TokenContentStateType.NO;
                rs.Msg = "无效的token值";
                return rs;
            }


            // Maltose:UserToken:ALLMP_47_35b8a1d7c715a909ef7f6a9bfdea76bf

            //刷新token
            if (type == ValidateType.RefreshToken)
            {
                //小于10分钟重新刷新
                if ((data.ExpireDateTime - DateTime.Now).TotalMinutes <= 10)
                {
                    var guid = Guid.NewGuid().ToString().Replace("-", "");
                    var newKey = $"{rawKey}_{guid}";
                    var newToken = CreateTokenString(newKey);
                    var conten = new DynamicTokenCache<object>()
                    {
                        Token = newToken,
                        ExpireDateTime = DateTime.Now.AddSeconds(ExpireTime),
                        Data = data.Data
                    };

                    UseCache.Instance.Add(newKey, conten.ToJson(), TimeSpan.FromSeconds(ExpireTime));

                    rs.Token = newToken;
                    return rs;
                }
            }

            rs.Token = token;
            return rs;
        }

        /// <summary>
        /// 删除token
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public bool Delete(string token)
        {
            var rawKey = GetRealKey(token);
            return UseCache.Instance.Delete(rawKey);
        }
    }
}
